package com.atguigu.tingshu.user.service.impl;

import java.util.Date;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.common.util.MongoUtil;
import com.atguigu.tingshu.model.user.UserListenProcess;
import com.atguigu.tingshu.user.service.UserListenProcessService;
import com.atguigu.tingshu.vo.album.TrackStatMqVo;
import com.atguigu.tingshu.vo.user.UserListenProcessVo;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@SuppressWarnings({"unchecked", "rawtypes"})
@Slf4j
public class UserListenProcessServiceImpl implements UserListenProcessService {

    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RabbitService rabbitService;

    @Override
    public BigDecimal getTrackBreakSecond(Long trackId) {
        Long userId = AuthContextHolder.getUserId();
        Criteria criteria = Criteria
                .where("userId").is(userId)
                .and("trackId").is(trackId);
        Query query = new Query(criteria);
        String collectionName = MongoUtil
                .getCollectionName(MongoUtil
                        .MongoCollectionEnum
                        .USER_LISTEN_PROCESS, userId);
        UserListenProcess userListenProcess = mongoTemplate
                .findOne(query,
                        UserListenProcess.class,
                        collectionName);
//        if (userListenProcess == null){
//            return new BigDecimal("0.0");
//        }
//        return userListenProcess.getBreakSecond();
        return userListenProcess == null ?
                new BigDecimal("0.0") :
                userListenProcess.getBreakSecond();
    }

    @Override
    public void updateListenProcess(UserListenProcessVo userListenProcessVo) {
        Long userId = AuthContextHolder.getUserId();
        Criteria criteria = Criteria
                .where("userId").is(userId)
                .and("trackId").is(userListenProcessVo.getTrackId());
        Query query = new Query(criteria);
        String collectionName = MongoUtil.getCollectionName(
                MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS,
                userId);
        UserListenProcess userListenProcess = mongoTemplate.findOne(query, UserListenProcess.class, collectionName);
        if (userListenProcess == null) {
            userListenProcess = new UserListenProcess();
            userListenProcess.setId(ObjectId.get().toString());
            userListenProcess.setUserId(userId);
            userListenProcess.setAlbumId(userListenProcessVo.getAlbumId());
            userListenProcess.setTrackId(userListenProcessVo.getTrackId());
            userListenProcess.setBreakSecond(userListenProcessVo.getBreakSecond());
            userListenProcess.setIsShow(1);
            userListenProcess.setCreateTime(new Date());
            userListenProcess.setUpdateTime(new Date());
            mongoTemplate.save(userListenProcess, collectionName);
            log.info("保存播放进度到Mongo中成功");
        } else {
            userListenProcess.setUpdateTime(new Date());
            userListenProcess.setBreakSecond(userListenProcessVo.getBreakSecond());
            // save() 如果文档id不存在 就是保存 如果文档id 就是修改
            mongoTemplate.save(userListenProcess, collectionName);
            log.info("修改播放进度到Mongo中成功");
        }
        //  修改MySQL中声音/专辑的播放量（异步发送消息给下游专辑微服务更新声音和专辑的播放量）
        // 使用redis中bitmap结构实现幂等性
        String bitmapKey = new DateTime().toString("yyyyMMdd") + ":" + userListenProcessVo.getTrackId();
        Boolean aBoolean = redisTemplate.opsForValue().setBit(bitmapKey, userId, true);
        if (!aBoolean){
            redisTemplate.expire(bitmapKey,1, TimeUnit.DAYS);
            //当天用户第一次播放该声音
            TrackStatMqVo trackStatMqVo = prepareStatMsgDto(userListenProcessVo);
            rabbitService.sendMessage(
                    MqConst.EXCHANGE_TRACK,
                    MqConst.ROUTING_TRACK_STAT_UPDATE,
                    JSONObject.toJSONString(trackStatMqVo));
        }
    }

    @Override
    public Map<String, Object> getLatelyTrack() {
        Long userId = AuthContextHolder.getUserId();
        Criteria criteria = Criteria.where("userId").is(userId);
        Query query = new Query(criteria);
        Sort sort = Sort.by(Sort.Direction.DESC, "updateTime");
        query.with(sort);
        String collectionName = MongoUtil.getCollectionName(MongoUtil.MongoCollectionEnum.USER_LISTEN_PROCESS, userId);
        UserListenProcess userListenProcess = mongoTemplate.findOne(query, UserListenProcess.class, collectionName);
        if (userListenProcess == null){
            return new HashMap<>();
        }
        HashMap<String, Object> map = new HashMap<>();
        map.put("trackId",userListenProcess.getTrackId());
        map.put("albumId",userListenProcess.getUserId());
        return map;
    }

    /**
     * 封装消息对象
     * @param userListenProcessVo 播放进度对象
     * @return TrackStatMqVo
     */
    private TrackStatMqVo prepareStatMsgDto(UserListenProcessVo userListenProcessVo) {
        TrackStatMqVo trackStatMqVo = new TrackStatMqVo();
        trackStatMqVo.setBusinessNo(UUID.randomUUID().toString().replaceAll("-",""));//业务编号
        trackStatMqVo.setAlbumId(userListenProcessVo.getAlbumId());
        trackStatMqVo.setTrackId(userListenProcessVo.getTrackId());
        trackStatMqVo.setStatType(SystemConstant.ALBUM_STAT_PLAY);
        trackStatMqVo.setCount(1);
        return trackStatMqVo;
    }
}
